const {ccclass, property} = cc._decorator;

import Group from "./custom/Group";
import { ResManager } from "./custom/ResManager";
import YSortCameraGroup from "./custom/YSortCameraGroup";
import Player from "./Player";
import Global from "./settings"
import { choice, import_csv_layout, getTime, spritecollide } from './support';
import Tile from "./tile";
import Enemy from './enemy';
import Weapon from './weapon';
import AnimationPlayer from './particles';
import MagicPlayer from './magic';
import UI from './ui';
import UpGrade from './upgrade';
import GameEvent from './custom/GameEvent';
import SoundManager from './custom/SoundManger';
import GamePad from './custom/GamePad';

let TILESIZE = Global.TILESIZE

@ccclass
export default class Level extends cc.Component {

    game_paused = false
    layouts = {}
    graphics = {}

    visible_sprites : YSortCameraGroup = null
    attackable_sprites : Group = null
    obstacle_sprites : Group = null

    current_attack : Weapon = null
    attack_sprites

    player : Player = null

    animation_player : AnimationPlayer
    magic_player : MagicPlayer

    ui : UI
    upgrade : UpGrade

    @property(cc.Node)
    display_surface : cc.Node = null
    
    protected start(): void {
    }

    init() {
        this.display_surface.setContentSize(Global.WIDTH,Global.HEIGTH)
        
        this.visible_sprites = this.node.getChildByName('visible_sprites').getComponent(YSortCameraGroup)
        this.attackable_sprites = this.node.getChildByName('attackable_sprites').getComponent(Group)
        this.obstacle_sprites = this.node.getChildByName('obstacle_sprites').getComponent(Group)
        this.attack_sprites = this.node.getChildByName('attack_sprites').getComponent(Group)
        

		// user interface 
		this.ui = new UI()

		// particles
		this.animation_player = new AnimationPlayer()
		this.magic_player = new MagicPlayer(this.animation_player)

        this.create_map()

        cc.director.on(GameEvent.key_menu, this.toggle_menu.bind(this), this)
    }

    create_map() {

        let res = ResManager.getInstance().getRes()

        this.layouts = {

			'boundary': import_csv_layout(res["map"]["map_FloorBlocks"].text),
			'grass': import_csv_layout(res["map"]["map_Grass"].text),
			'object': import_csv_layout(res["map"]["map_Objects"].text),
			'entities': import_csv_layout(res["map"]["map_Entities"].text)
		}

		this.graphics = {
			'grass': res["grass"],
			'objects': res["objects"]
		}

        for(let style in this.layouts) {
            let layout = this.layouts[style]
            for(let row_index=0; row_index<layout.length; row_index++) {
                let row = layout[row_index]
                for(let col_index=0; col_index<row.length; col_index++) {
                    let col = row[col_index]

                    let x = 0
                    let y = 0

                    if(col != '-1') {
                        x = col_index * TILESIZE
                        y = row_index * TILESIZE

                        if(style == 'boundary') {
                            new Tile([x, y],[this.obstacle_sprites],'invisible')
                        }
                        
                        if(style == 'grass') {

                            let random_grass_image = choice(this.graphics['grass'])
                            new Tile(
                                [x, y],
                                [this.visible_sprites,this.obstacle_sprites,this.attackable_sprites],
                                'grass',
                                random_grass_image)
                        }

                        if (style == 'object') {

                            let value = Math.floor(col)
                            let key = "0"
                            if(Math.floor(col) < 10) {
                                if(value != 0) {
                                    key = "0" + value
                                }
                            } else {
                                key = "" + value
                            }

                            let surf = this.graphics['objects'][key]
                            if(surf == undefined) {
                                console.log("object col=" , col)
                            }
                            new Tile([x,y],[this.visible_sprites,this.obstacle_sprites],'object',surf)


                        }

                        if(style == 'entities') {
                            if (col == '394') {
                                
                                this.player = new Player(
                                    [x, y],
                                    [this.visible_sprites],
                                    this.obstacle_sprites,
                                    this.create_attack.bind(this),
                                    this.destroy_attack.bind(this),
                                    this.create_magic.bind(this),
                                    this)
                            } else {

                                let monster_name
                                if (col == '390') { monster_name = 'bamboo'}
                                else if(col == '391') { monster_name = 'spirit'}
                                else if(col == '392') { monster_name ='raccoon'}
                                else {monster_name = 'squid'}

                                new Enemy(
                                    monster_name,
                                    [x,y],
                                    [this.visible_sprites,this.attackable_sprites],
                                    this.obstacle_sprites,
                                    this.damage_player.bind(this),
                                    this.trigger_death_particles.bind(this),
                                    this.add_exp.bind(this))
                            }
                        }
                    }
                }        
            }        
        }
    
    }

    create_attack() {
        this.current_attack = new Weapon(this.player,[this.visible_sprites,this.attack_sprites])
    }

    create_magic(style,strength,cost) {
        if(style == 'heal') {
            this.magic_player.heal(this.player,strength,cost,[this.visible_sprites])
        }

        if(style == 'flame') {
            this.magic_player.flame(this.player,cost,[this.visible_sprites,this.attack_sprites])
        }
    }

    destroy_attack(this){
        if(this.current_attack) {
            this.current_attack.kill()
            this.current_attack = null
        }
    }

    damage_player(amount, attack_type, attack_sound) {
        if(this.player.vulnerable) {
            this.player.health -= amount
			this.player.vulnerable = false
			this.player.hurt_time = getTime()
			this.animation_player.create_particles(attack_type, [this.player.rect.center.x, this.player.rect.center.y],[this.visible_sprites])
            SoundManager.getInstance().playEffect(attack_sound)
        }
    }

    trigger_death_particles(pos,particle_type) {
        this. animation_player.create_particles(particle_type,pos,this.visible_sprites)
    }

    add_exp(amount) {
        this.player.exp += amount
    }

    toggle_menu() {
        this.game_paused = !this.game_paused 
    }

    run(dt) {
		this.ui.display(this.player)
        this.visible_sprites.custom_draw(this.player)
		
		if(this.game_paused){

            if(this.upgrade == null) {
                this.upgrade = new UpGrade(this.player)
            }

			this.upgrade.display()
        }
		else {
			this.visible_sprites.update(dt)
			this.visible_sprites.enemy_update(this.player)
			this.player_attack_logic()
            
            if(this.upgrade) {
                this.upgrade.hide()
            }
        }
    }

    player_attack_logic() {
        if(this.attack_sprites) {
            for(let attack_sprite of this.attack_sprites.childList) {
                let collision_sprites = spritecollide(attack_sprite,this.attackable_sprites.childList)
                if(collision_sprites) {
                    for(let target_sprite of collision_sprites) {
                        if(target_sprite.sprite_type == 'grass') {
                            let randomCount = Math.floor(Math.random() * 4) + 3 
                            for(let i=0; i<randomCount; i++) {
                                this.animation_player.create_grass_particles([target_sprite.x, target_sprite.y+75],[this.visible_sprites])
                            }
                            target_sprite.kill()
                        } else {
                            target_sprite.get_damage(this.player,attack_sprite.sprite_type)
                        }
                    }
                }
            }
        }
    }

}
